#include "GUIFeeder.h"	

/**
 * @fn	GUIFeeder::GUIFeeder(int startX, int startY, FeederAgent* myAgent, GUILane* myTopLane,
 * 		GUILane* myBottomLane, int myFeederNumber, QGraphicsScene *scene)
 *
 * @brief	Constructor.
 *
 * @author	Justin Chen
 *
 * @param	startX					The start x coordinate.
 * @param	startY					The start y coordinate.
 * @param [in,out]	myAgent			If non-null, my agent.
 * @param [in,out]	myTopLane   	If non-null, my top lane.
 * @param [in,out]	myBottomLane	If non-null, my bottom lane.
 * @param	myFeederNumber			The animation.
 * @param [in,out]	scene			(optional)  If non-null, the scene.
 */

GUIFeeder::GUIFeeder(int startX, int startY, FeederAgent* myAgent, GUILane* myTopLane, GUILane* myBottomLane, int myFeederNumber, FeederColor feederColor)
	: GUIBase()
{
	switch (feederColor)
	{
		case FeederColor_Yellow: loadImage("Resources/Sprites/Feeder/Feeder1.png"); break;
		case FeederColor_Purple: loadImage("Resources/Sprites/Feeder/Feeder2.png"); break;
		case FeederColor_Green: loadImage("Resources/Sprites/Feeder/Feeder3.png"); break;
		case FeederColor_Red: loadImage("Resources/Sprites/Feeder/Feeder4.png"); break;
	}

	// Load and set up diverter pixmap.
	imgDiverter = new QGraphicsPixmapItem(QPixmap("Resources/Sprites/Feeder/Diverter.png"));
	imgDiverter->setZValue(ZVALUE_DIVERTER);
	imgDiverter->hide();
	factoryScene->addItem(imgDiverter);

	this->setOriginCenter();

	this->setX(startX);
	this->setY(startY);
	this->setZValue(ZVALUE_FEEDER);

	agent = myAgent;
	this->setGUIBaseAgent(agent);
	topLane = myTopLane;
	bottomLane = myBottomLane;
	feederNumber = myFeederNumber;
	angle = 0;
	purgeBin = NULL;
	broken=false;

	state = FeederOff;

	show();
}

/**
 * @fn	GUIFeeder::~GUIFeeder()
 *
 * @brief	Destructor.
 *
 * @author	Justin Chen
 */

GUIFeeder::~GUIFeeder()
{

}

/**
 * @fn	void GUIFeeder::HereAreBinParts(std::vector<Part*> &parts)
 *
 * @brief	Gets parts from the bin.
 *
 * @author	Justin Chen
 *
 * @param [in,out]	parts	[in,out] If non-null, the parts.
 */

void GUIFeeder::HereAreBinParts(std::vector<Part*> &parts)
{
	int numOfParts = parts.size();
	for (int i = 0; i < numOfParts; i++)
	{
		partsInFeeder.push_back(parts.back());
		parts.pop_back();

		// Center the part in the feeder
		partsInFeeder[i]->setX(this->x() + this->boundingRect().width()/2 - partsInFeeder[i]->boundingRect().width()/2);
		partsInFeeder[i]->setY(this->y() + this->boundingRect().height()/2 - partsInFeeder[i]->boundingRect().height()/2);
	}
}

/**
 * @fn	void GUIFeeder::HereIsPurgeBin(Bin* bin)
 *
 * @brief	Here is purge bin.
 *
 * @author	Justin Chen
 *
 * @param [in,out]	bin	If non-null, the bin. If null, purge onto the floor.
 */

void GUIFeeder::HereIsPurgeBin(Bin* bin)
{
	purgeBin = bin;
}

/**
 * @fn	void GUIFeeder::DoDropInLane(int lane)
 *
 * @brief	Executes the drop in lane operation.
 *
 * @author	Justin Chen
 *
 * @param	lane	The lane to drop the parts in. 0=bottom lane, 1=top lane
 */

void GUIFeeder::DoDropInLane(int lane)
{
	state = FeederDropping;
	dropInThisLane = lane;
}

/**
 * @fn	void GUIFeeder::DoPurge()
 *
 * @brief	Executes the purge operation.
 *
 * @author	Justin Chen
 */

void GUIFeeder::DoPurge()
{
	state = FeederPurging;
}

/**
 * @fn	void GUIFeeder::DropAPart()
 *
 * @brief	Drop a part into the lane. Drop into the wrong lane if broken.
 *
 * @author	Justin Chen
 */

void GUIFeeder::DropAPart()
{
	// Drop parts until the feeder is empty
	if (!partsInFeeder.empty())
	{
		// Open the wrong hatch if broken
		if (!broken)
			openHatch(dropInThisLane);
		else
		{
			if (dropInThisLane == 0)
				openHatch(1);
			else
				openHatch(0);
		}

		Part* dropMe = partsInFeeder.back();
		bool partDroppable;

		// Drop in the wrong lane if the feeder is broken
		if (!broken)
			partDroppable = (dropInThisLane == 0) ? bottomLane->HereIsAPart(dropMe): topLane->HereIsAPart(dropMe);
		else
			partDroppable = (dropInThisLane == 0) ? topLane->HereIsAPart(dropMe): bottomLane->HereIsAPart(dropMe);

		if (partDroppable) // If the lane has space, drop the part
		{
			partsInFeeder.pop_back();
		}
	}
	// Then tell the agent that the parts have been moved and turn the feeder off
	else
	{
		state = FeederOff;
		agent->msgGUIHasMovedPart();
	}
}

/**
 * @fn	bool GUIFeeder::hasPurgeBin()
 *
 * @brief	Query if this object has purge bin.
 *
 * @author	Justin Chen
 *
 * @return	true if it has a purge bin, false if not.
 */

bool GUIFeeder::hasPurgeBin()
{
	if (purgeBin != NULL)
		return true;
	else
		return false;
}

/**
 * @fn	void GUIFeeder::Purge()
 *
 * @brief	Purges the feeder.
 *
 * @author	Justin Chen
 */

void GUIFeeder::Purge()
{
	// Move all the parts into the bin
	while (!partsInFeeder.empty())
	{
		if (purgeBin != NULL) // Just drop it on the floor if there is no purgeBin
		{
			purgeBin->AddPartToBin(partsInFeeder.back());
			partsInFeeder.back()->setPos(this->x() - purgeBin->x(), this->y() - purgeBin->y());
			partsInFeeder.back()->moveTo(0, 0);
		}
		else // Drop on floor
		{
			partsInFeeder.back()->PartFellOnFloor();
			partsInFeeder.back()->setMovementSpeed(10);
			partsInFeeder.back()->accelTo(this->x() + (rand() % 40) + 40, this->y() + (rand() % 80) - 40, -0.7, 0);
		}
		partsInFeeder.pop_back();
	}
	
	// Tell the agent that the feeder has purged and turn it off
	state = FeederOff;
	agent->msgGUIHasPurged();
}

/**
 * @fn	void GUIFeeder::openHatch(int lane)
 *
 * @brief	Opens a hatch.
 *
 * @author	Justin Chen
 *
 * @param	lane	The lane. 0=bottom, 1=top, -1=close hatches
 */

void GUIFeeder::openHatch(int lane)
{
	switch (lane)
	{
	case 0: // Bottom hatch
		imgDiverter->setPos(this->x() - this->boundingRect().width()/2 - imgDiverter->boundingRect().width() + 10, this->y() - 5);
		imgDiverter->show();
		break;
	case 1: // Top hatch
		imgDiverter->setPos(this->x() - this->boundingRect().width()/2 - imgDiverter->boundingRect().width() + 10, this->y() - this->boundingRect().height()/2);
		imgDiverter->show();
		break;
	case -1: // Close hatches
		imgDiverter->hide();
		break;
	}
}

/**
 * @fn	void GUIFeeder::advance(int phase)
 *
 * @brief	Advances.
 *
 * @author	Justin Chen
 *
 * @param	phase	The phase.
 */

void GUIFeeder::advance(int phase)
{
	GUIBase::advance(phase);

	// Run once, not twice per frame
	if (phase == 1)
	{
		// Spin the parts!
		if (angle < 6.28)
			angle += 0.1;
		else
			angle = 0;

		for(int i = 0; i < partsInFeeder.size(); i++)
		{
			partsInFeeder[i]->moveTo(30*cos(angle+i*6.28/partsInFeeder.size()) + this->x() - 10, 30*sin(angle+i*6.28/partsInFeeder.size()) + this->y());
			//partsInFeeder[i]->setX(20*cos(angle+i*6.28/partsInFeeder.size()) + this->x() - 10);
			//partsInFeeder[i]->setY(20*sin(angle+i*6.28/partsInFeeder.size()) + this->y());
		}

		// Determine what to do each frame
		switch (state)
		{
		case FeederOff:
			openHatch(-1);
			break;
		case FeederPurging:
			openHatch(-1);
			Purge();
			break;
		case FeederDropping:
			DropAPart();
			break;
		}
	}
}

/**
 * @fn	void GUIFeeder::DoBreak()
 *
 * @brief	Breaks the feeder.
 *
 * @author	Justin Chen
 */

void GUIFeeder::DoBreak()
{
	GUIBase::DoBreak();
}

/**
 * @fn	void GUIFeeder::DoFix()
 *
 * @brief	Fixes the feeder.
 *
 * @author	Justin Chen
 */

void GUIFeeder::DoFix()
{
	GUIBase::DoFix();
}
